package pso;

import java.io.File;

import discretePso.SATInstance;

public class PSOMinimize {
	private static BlackBoxFunction function;
	private static Functions functionType = Functions.MAXSAT;
	private static Point lowerBound;
	private static Point upperBound;
	private static int swarmSize = 40;
	private static int steps = 100;
	private static PointGenerator startingPointGenerator;
	private static PointGenerator startingVelocityGenerator;
	private static VelocityGenerators velocityGenerator = VelocityGenerators.RANDOM;
	private static PointGenerators pointGenerator = PointGenerators.RANDOM;
	private static BoundaryHandling boundaryHandling = BoundaryHandling.RANDOM;
	private static double mu = 0.728, c1 = 1.49, c2 = 1.49;
	private static int dimension = 3;
	private static File discretePSODataFile = new File("trunk/data/SAT/aim-50-1_6-yes1-1.cnf");
	
	
	public static void main(String[] args)
	{
		for(int i=2; i < args.length; i += 2)
		{
			if(args[i-1].equalsIgnoreCase("-swarmsize")){
				swarmSize = Integer.parseInt(args[i]);
			}else if(args[i-1].equalsIgnoreCase("-dimension")){
				dimension = Integer.parseInt(args[i]);
			}else if(args[i-1].equalsIgnoreCase("-function")){
				if(args[i].equalsIgnoreCase("sphere")){
					functionType = Functions.SPHERE;
				}else if(args[i].equalsIgnoreCase("rosenbrock")){
					functionType = Functions.ROSENBROCK;
				}else if(args[i].equalsIgnoreCase("rastrigin")){
					functionType = Functions.RASTRIGIN;
				}else if(args[i].equalsIgnoreCase("pizza")){
					functionType = Functions.PIZZA;
				}else if(args[i].equalsIgnoreCase("schwefel")){
					functionType = Functions.SCHWEFEL;
				}else{
					System.out.println("Unknown function: " + args[i]);
					System.out.println("Using SPHERE as default.");
					functionType = Functions.SPHERE;
				}
			}else if(args[i-1].equalsIgnoreCase( "-startingPointDistribution")){
				if(args[i].equalsIgnoreCase("random")){
					pointGenerator = PointGenerators.RANDOM;
				}else{
					System.out.println("Unknown starting point distribution: " + args[i]);
					System.out.println("Using RANDOM as default.");
					pointGenerator = PointGenerators.RANDOM;
				}
			}else if(args[i-1].equalsIgnoreCase( "-startingVelocityDistribution")){
				if(args[i].equalsIgnoreCase("random")){
					velocityGenerator = VelocityGenerators.RANDOM;
				}else{
					System.out.println("Unknown starting velocity distribution: " + args[i]);
					System.out.println("Using RANDOM as default.");
					velocityGenerator = VelocityGenerators.RANDOM;
				}
			}else if(args[i-1].equalsIgnoreCase( "-boundary")){
				boundaryHandling = BoundaryHandling.BOUNCE;
			}else if(args[i-1].equalsIgnoreCase( "-mu")){
				mu = Double.parseDouble(args[i]);
			}else if(args[i-1].equalsIgnoreCase( "-c1")){
				c1 = Double.parseDouble(args[i]);
			}else if(args[i-1].equalsIgnoreCase( "-c2")){
				c2 = Double.parseDouble(args[i]);
			}else if(args[i-1].equalsIgnoreCase( "-steps")){
				steps = Integer.parseInt(args[i]);
			}else{
				System.out.println("Usage: ");
				System.out.println("-mu constant ");
				System.out.println("-c1 constant ");
				System.out.println("-c2 constant ");
				System.out.println("-steps number of steps ");
				System.out.println("-boundary [BOUNCE/RANDOM/MODULO/IGNORE/STICKY_WALL] ");
				System.out.println("-range size of the search space ");
				System.out.println("-function [SPHERE/ROSENBROCK/PIZZA/SCHWEFEL/RASTRIGIN/MAXSAT] ");
				System.out.println("-dimension dimension of the search space ");
				System.out.println("-swarmsize number of particles ");
			}	
		}
		
		
		//SPHERE, ROSENBROCK, RASTRIGIN, SCHWEFEL, PIZZA
		switch(functionType){
		case SPHERE:
			function = new Sphere(dimension);
			break;
			
		case ROSENBROCK:
			function = new Rosenbrock(dimension);
			break;
			
		case RASTRIGIN:
			function = new Rastrigin(dimension);
			break;
		
		case SCHWEFEL:
			function = new Schwefel(dimension);
			break;
			
		case PIZZA:
			function = new Pizza(dimension);
			break;
			
		case MAXSAT:
			SATInstance satInstance = new SATInstance(discretePSODataFile);
			function = new MAXSAT(satInstance);
			break;
			
		default:
			function = new Sphere(dimension);
		}
		
		//Parse range to create Points as boundary
		lowerBound = function.getLowerBound();
		upperBound = function.getUpperBound();
		
		
		//RANDOM
		switch(velocityGenerator){
		case RANDOM:
			startingVelocityGenerator = new RandomPointGenerator(lowerBound, upperBound);
			break;
		
		default:
			startingVelocityGenerator = new RandomPointGenerator(lowerBound.scale(.1), upperBound.scale(.1));
		}
		
		//RANDOM
		switch(pointGenerator){
		case RANDOM:
			startingPointGenerator = new RandomPointGenerator(lowerBound, upperBound);
			break;
		
		default:
			startingPointGenerator = new RandomPointGenerator(lowerBound, upperBound);
		}
		
		
		
		ParticleSwarmOptimization pso = new ParticleSwarmOptimization();
		
		
		PSOResult res = pso.evaluateParticelSwarmOptimization(
				function, 
				lowerBound, 
				upperBound,
				swarmSize, 
				startingPointGenerator,
				startingVelocityGenerator, 
				boundaryHandling, 
				steps,
				mu, 
				c1, 
				c2);
		
		
		System.out.println("Minimal Value: " + res.optimalValue);
		System.out.println("At: " + res.optimalPoint.toString());
		
		/*
		 * Optional output for MAXSAT
		 * */
		/*
		SATInstance testInstance = new SATInstance(discretePSODataFile);
		boolean[] assignment = new boolean[res.optimalPoint.getDimension()];
		for(int i=0; i<res.optimalPoint.getDimension(); i++){
			assignment[i] = (res.optimalPoint.getCoordinate(i) > 0.5);
		}
		int numSatisfiedClauses = testInstance.evaluate(assignment);
		System.out.println(numSatisfiedClauses);
		System.out.println(assignment.toString());
		*/
	}
}
